#include "remote_vendor.h"

/* clang-format off */
#include <goahead.h>

static vendor::MyOpt myOpts_[] = {
    {"help",     no_argument,       'h', "[options] [documents] [IPaddress][:port]..."       },
    {"auth",     required_argument, 0,   "User and role configuration"                       },
    {"debug",    no_argument,       0,   "Run in debug mode"                                 },
    {"home",     required_argument, 0,   "Change to directory to run"                        },
    {"log",      required_argument, 0,   "logFile:level, Log to file file at verbosity level"},
    {"route",    required_argument, 0,   "route file"                                        },
    {"port",     required_argument, 0,   "set port, default: 8880"                           },
    {"delay",    required_argument, 0,   "delay secs to quit"                                },
    {"document", required_argument, 0,   "document"                                          },
    {"verbose",  required_argument, 0,   "Same as --log stderr:2"                            },
    {"version",  no_argument,       0,   "version information"                               }
};
/* clang-format on */

const std::string DAS_WEB_DOCUMENT = ".";
const int32_t DAS_WEB_PORT = 8880;
const int32_t DAS_WEB_SSL_PORT = 8881;

RemoteVendor::RemoteVendor() : listenPort_(DAS_WEB_PORT), docFile_(DAS_WEB_DOCUMENT), homeDir_(VENDOR_WWW_PATH), duration_(0)
{
    routeFile_ = VENDOR_WWW_PATH + "route.txt";
    authFile_ = VENDOR_WWW_PATH + "auth.txt";
    logSetPath(std::string(VENDOR_LOG_PATH).c_str());
    HTELINK_LOG_INFO("set log path: %s", VENDOR_LOG_PATH.c_str());
}

RemoteVendor::~RemoteVendor()
{
    finish_ = 1;
    websClose();
}

int RemoteVendor::ParseCmdline(const std::string &optname, const std::string &optarg)
{
    if (optname == "auth") {
        authFile_ = optarg;
    } else if (optname == "debug") {
        websSetDebug(1);
        debug_ = true;
    } else if (optname == "home") {
        homeDir_ = optarg;
        if (chdir(homeDir_.c_str()) < 0) {
            HTELINK_LOG_ERR("Cannot change directory to %s", homeDir_.c_str());
            exit(-1);
        }
        HTELINK_LOG_INFO("change to dir: %s", homeDir_.c_str());
    } else if (optname == "log") {
        logSetPath(optarg.c_str());
        HTELINK_LOG_INFO("set log path: %s", optarg.c_str());
    } else if (optname == "route") {
        routeFile_ = optarg;
    } else if (optname == "document") {
        docFile_ = optarg;
    } else if (optname == "port") {
        listenPort_ = atoi(optarg.c_str());
    } else if (optname == "port") {
        duration_ = atoi(optarg.c_str());
    } else if (optname == "verbose") {
        logSetPath(optarg.c_str());
        HTELINK_LOG_INFO("set log path: %s", optarg.c_str());
    } else if (optname == "version") {
    } else {
        exit(-1);
    }
    return 0;
}

vendor::MyOpt *RemoteVendor::GetOpts()
{
    return myOpts_;
}

int RemoteVendor::GetOptSize()
{
    return sizeof(myOpts_) / sizeof(myOpts_[0]);
}

void sigHandler(int sig)
{
    HTELINK_LOG_DEBUG("sigHandler, %d", sig);
}

int RemoteVendor::Run()
{
    finish_ = 0;
    signal(SIGTERM, sigHandler);
    signal(SIGPIPE, SIG_IGN);
    // _fmode = _O_BINARY;

    HTELINK_LOG_INFO("webs Open %s", docFile_.c_str());
    if (websOpen(docFile_.empty() ? nullptr : docFile_.c_str(), routeFile_.c_str()) < 0) {
        HTELINK_LOG_ERR("Cannot initialize server. Exiting.");
        return -1;
    }
    websSetPasswordStoreVerify([](Webs *wp) -> bool {
        return WebHandler::instance()->LoginVerify(wp);
    });
    websSetIndex("index.html");
    DefineWeb();

    HTELINK_LOG_INFO("webs Load %s", authFile_.c_str());
    if (websLoad(authFile_.c_str()) < 0) {
        HTELINK_LOG_ERR("Cannot load %s", authFile_.c_str());
        return -1;
    }

    /* clang-format off */
    std::string listHosts[] = {
        std::string("http://*:") + std::to_string(listenPort_),
        std::string("https://*:") + std::to_string(DAS_WEB_SSL_PORT)
        };
    /* clang-format on */

    for (std::string &host : listHosts) {
        HTELINK_LOG_INFO("webs Listen %s", host.c_str());
        if (websListen(host.c_str()) < 0) {
            HTELINK_LOG_ERR("Cannot listen %s", host.c_str());
            return -1;
        }
    }

    DumpWebVendor();
    if (duration_ > 0) {
        HTELINK_LOG_INFO("Running for %d secs\n", duration_);
        websStartEvent(
            duration_ * 1000,
            [](void *data, int id) {
                websStopEvent(id);
            },
            &finish_);
    }
    websServiceEvents(&finish_);
    HTELINK_LOG_INFO("webs service exit, err = %s", strerror(errno));
    return 0;
}

std::string RemoteVendor::Name()
{
    return "web-deamon";
}

void RemoteVendor::Stop(int signal)
{
    HTELINK_LOG_INFO("webs exit, signal = %d", signal);
    finish_ = 1;
}

void RemoteVendor::DumpWebVendor(void)
{
    char home[ME_GOAHEAD_LIMIT_STRING];

    getcwd(home, sizeof(home));
    HTELINK_LOG_INFO("Configuration for %s", PRODUCT_NAME);
    HTELINK_LOG_INFO("---------------------------------------------");
    HTELINK_LOG_INFO("Version:            %s", DAS_VERSION);
    HTELINK_LOG_INFO("BuildType:          %s", ME_DEBUG ? "Debug" : "Release");
    HTELINK_LOG_INFO("CPU:                %s", ME_CPU);
    HTELINK_LOG_INFO("OS:                 %s", ME_OS);
    HTELINK_LOG_INFO("Host:               %s", websGetServerUrl());
    HTELINK_LOG_INFO("Directory:          %s", home);
    HTELINK_LOG_INFO("Documents:          %s", websGetDocuments());
    HTELINK_LOG_INFO("Configure:          %s", ME_CONFIG_CMD);
    HTELINK_LOG_INFO("---------------------------------------------");
}

void RemoteVendor::DefineWeb()
{
    if (debug_) {
        websDefineHandler(
            "debug",
            [](Webs *wp) -> bool {
                HTELINK_LOG_DEBUG("webs debug path: %s, prefix = %s, user = %s, password = %s, decode = %d method = "
                                  "%s, protocol = %s",
                    wp->path == nullptr ? "" : wp->path, wp->route->prefix, wp->username, wp->password, wp->encoded,
                    wp->method, wp->protocol);
                return false;
            },
            0, 0, 0);
    }
    //
    websDefineHandler(
        "uid", 0,
        [](Webs *wp) -> bool {
            HTELINK_LOG_DEBUG("webs uid path: %s, prefix = %s, user = %s, method = %s, protocol = %s",
                wp->path == nullptr ? "" : wp->path, wp->route->prefix, wp->username, wp->method, wp->protocol);
            return WebHandler::instance()->WebResult(wp, "/uid/");
        },
        0, 0);
    websDefineHandler(
        "ajax", 0,
        [](Webs *wp) -> bool {
            HTELINK_LOG_DEBUG("webs ajax path: %s, prefix = %s, user = %s, method = %s, protocol = %s",
                wp->path == nullptr ? "" : wp->path, wp->route->prefix, wp->username, wp->method, wp->protocol);
            return WebHandler::instance()->WebResult(wp, "/ajax/");
        },
        0, 0);

    websAddRoute("/ajax", "ajax", 0);
    websAddRoute("/uid", "uid", 0);
    if (debug_) {
        websAddRoute("/", "debug", 0);
    }
    websAddRoute("/", "file", -1);
}
